🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / .github / workflows / create-or-promote-release.yml
Displaying Raw • Download
.github/workflows/create-or-promote-release.yml 817b3ea120d5efc18b3885b99f25a9db14e042a6 (817b3ea1) Text, 7.75 KB
Tff7b72nameTb4b4b4: Ta5d6ffCreateTa5d6ff Ta5d6fforTa5d6ff Ta5d6ffPromoteTa5d6ff Ta5d6ffRelease
Tff7b72onTb4b4b4:
Tff7b72workflow_dispatchTb4b4b4:
Tff7b72inputsTb4b4b4:
Tff7b72base_versionTb4b4b4:
Tff7b72descriptionTb4b4b4: Ta5d6ff'Ta5d6ffBaseTe6edf3 Ta5d6ffversionTe6edf3 Ta5d6ffforTe6edf3 Ta5d6fftheTe6edf3 Ta5d6ffreleaseTe6edf3 Ta5d6ff(e.g.,Te6edf3 Ta5d6ff2.3.0)Ta5d6ff'
Tff7b72requiredTb4b4b4: Ta5d6fftrue
Tff7b72channelTb4b4b4:
Tff7b72descriptionTb4b4b4: Ta5d6ff'Ta5d6ffTheTe6edf3 Ta5d6ffchannelTe6edf3 Ta5d6fftoTe6edf3 Ta5d6ffcreateTe6edf3 Ta5d6ffaTe6edf3 Ta5d6ffreleaseTe6edf3 Ta5d6ffforTe6edf3 Ta5d6fforTe6edf3 Ta5d6ffpromoteTe6edf3 Ta5d6fftoTa5d6ff'
Tff7b72requiredTb4b4b4: Ta5d6fftrue
Tff7b72typeTb4b4b4: Ta5d6ffchoice
Tff7b72optionsTb4b4b4:
Tb4b4b4- Ta5d6ffinternal
Tb4b4b4- Ta5d6ffclosed
Tb4b4b4- Ta5d6ffopen
Tb4b4b4- Ta5d6ffproduction
Tff7b72dry_runTb4b4b4:
Tff7b72descriptionTb4b4b4: Ta5d6ff'Ta5d6ffIfTe6edf3 Ta5d6fftrue,Te6edf3 Ta5d6ffcalculatesTe6edf3 Ta5d6fftheTe6edf3 Ta5d6fftagTe6edf3 Ta5d6ffbutTe6edf3 Ta5d6ffdoesTe6edf3 Ta5d6ffnotTe6edf3 Ta5d6ffpushTe6edf3 Ta5d6ffitTe6edf3 Ta5d6fforTe6edf3 Ta5d6ffstartTe6edf3 Ta5d6fftheTe6edf3 Ta5d6ffreleaseTa5d6ff'
Tff7b72requiredTb4b4b4: Ta5d6fftrue
Tff7b72typeTb4b4b4: Ta5d6ffboolean
Tff7b72defaultTb4b4b4: Ta5d6fffalse
Tff7b72no_review_in_flightTb4b4b4:
Tff7b72descriptionTb4b4b4: Ta5d6ff'Ta5d6ffPromotionsTe6edf3 Ta5d6ffonly:Te6edf3 Ta5d6ffITe6edf3 Ta5d6ffcheckedTe6edf3 Ta5d6ffPublishingTe6edf3 Ta5d6ffoverviewTe6edf3 Ta5d6ff>Te6edf3 Ta5d6ffSubmissionTe6edf3 Ta5d6ffactivityTe6edf3 Ta5d6ffandTe6edf3 Ta5d6ffnoTe6edf3 Ta5d6ffsubmissionTe6edf3 Ta5d6ffisTe6edf3 Ta5d6ffInTe6edf3 Ta5d6ffreview.Te6edf3 Ta5d6ffEveryTe6edf3 Ta5d6ffpromotionTe6edf3 Ta5d6ffcreatesTe6edf3 Ta5d6ffaTe6edf3 Ta5d6ffnewTe6edf3 Ta5d6ffPlayTe6edf3 Ta5d6ffsubmission,Te6edf3 Ta5d6ffwhichTe6edf3 Ta5d6ffCANCELSTe6edf3 Ta5d6ffandTe6edf3 Ta5d6ffRESTARTSTe6edf3 Ta5d6ffanyTe6edf3 Ta5d6ffreviewTe6edf3 Ta5d6ffinTe6edf3 Ta5d6ffflight.Ta5d6ff'
Tff7b72requiredTb4b4b4: Ta5d6fffalse
Tff7b72typeTb4b4b4: Ta5d6ffboolean
Tff7b72defaultTb4b4b4: Ta5d6fffalse
Tff7b72permissionsTb4b4b4:
Tff7b72contentsTb4b4b4: Ta5d6ffwrite
Tff7b72pull-requestsTb4b4b4: Ta5d6ffwrite
Tff7b72statusesTb4b4b4: Ta5d6ffwrite
Tff7b72id-tokenTb4b4b4: Ta5d6ffwrite
Tff7b72attestationsTb4b4b4: Ta5d6ffwrite
T8b949e# Never allow two release pipelines to run at once — they race on tags,
T8b949e# release objects, and Play track state. Later dispatches queue.
Tff7b72concurrencyTb4b4b4:
Tff7b72groupTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffgithub.workflowTa5d6ff Ta5d6ff}}
Tff7b72cancel-in-progressTb4b4b4: Ta5d6fffalse
Tff7b72jobsTb4b4b4:
Tff7b72determine-tagsTb4b4b4:
Tff7b72runs-onTb4b4b4: Ta5d6ffubuntu-24.04-arm
Tff7b72timeout-minutesTb4b4b4: Ta5d6ff10
Tff7b72outputsTb4b4b4:
Tff7b72tag_to_processTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.calculate_tags.outputs.tag_to_processTa5d6ff Ta5d6ff}}
Tff7b72release_nameTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.calculate_tags.outputs.release_nameTa5d6ff Ta5d6ff}}
Tff7b72final_tagTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.calculate_tags.outputs.final_tagTa5d6ff Ta5d6ff}}
Tff7b72from_channelTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.calculate_tags.outputs.from_channelTa5d6ff Ta5d6ff}}
Tff7b72stepsTb4b4b4:
T8b949e# Internal releases are exempt: Play internal testing skips full review,
T8b949e# so only promotions (closed/open/production) can clobber an in-flight
T8b949e# review. Dry runs never reach Play.
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffRequireTa5d6ff Ta5d6ffreview-in-flightTa5d6ff Ta5d6ffconfirmationTa5d6ff Ta5d6ffforTa5d6ff Ta5d6ffpromotions
Tff7b72ifTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ff!inputs.dry_runTa5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffinputs.channelTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff'internal'Ta5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ff!inputs.no_review_in_flightTa5d6ff Ta5d6ff}}
Tff7b72runTb4b4b4: Tb4b4b4|
Tff7b72echo "::error::Promotion blocked: confirm no Play review is in flight. Check Play Console > Publishing overview > Submission activity — if a submission shows 'In review', WAIT (a new promotion cancels it and restarts the clock). If clear, re-dispatch with 'no_review_in_flight' checked."
Tff7b72exit 1
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffCheckoutTa5d6ff Ta5d6ffcode
Tff7b72usesTb4b4b4: Ta5d6ffactions/checkout@v7.0.1
Tff7b72withTb4b4b4:
Tff7b72fetch-depthTb4b4b4: Ta5d6ff0
Tff7b72tokenTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsecrets.CROWDIN_GITHUB_TOKENTa5d6ff Ta5d6ff}}
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffCalculateTa5d6ff Ta5d6fftags
Tff7b72idTb4b4b4: Ta5d6ffcalculate_tags
Tff7b72runTb4b4b4: Tb4b4b4|
Tff7b72BASE_VERSION="${{ inputs.base_version }}"
Tff7b72CHANNEL="${{ inputs.channel }}"
Tff7b72if [[ "$CHANNEL" == "internal" ]]; then
Tff7b72# This is a new build, create a new internal tag
Tff7b72LATEST_TAG=$(git tag --list "v${BASE_VERSION}-internal.*" --sort=-v:refname | head -n 1)
Tff7b72if [ -z "$LATEST_TAG" ]; then
Tff7b72INCREMENT=1
Tff7b72else
Tff7b72INCREMENT=$(echo "$LATEST_TAG" | sed -n "s/.*-internal\.\([0-9]*\)/\1/p" | awk '{print $1+1}')
Tff7b72fi
Tff7b72NEW_TAG="v${BASE_VERSION}-internal.${INCREMENT}"
Tff7b72echo "Calculated new tag: $NEW_TAG"
Tff7b72{
Tff7b72echo "tag_to_process=$NEW_TAG"
Tff7b72echo "release_name=$NEW_TAG"
Tff7b72echo "final_tag=$NEW_TAG"
Tff7b72} >> "$GITHUB_OUTPUT"
Tff7b72else
Tff7b72# This is a promotion, find the latest tag from the previous channel to promote
Tff7b72FROM_CHANNEL="internal"
Tff7b72if [[ "$CHANNEL" == "open" ]]; then
Tff7b72FROM_CHANNEL="closed"
Tff7b72elif [[ "$CHANNEL" == "production" ]]; then
Tff7b72FROM_CHANNEL="open"
Tff7b72fi
Tff7b72
Tff7b72LATEST_TAG_TO_PROMOTE=$(git tag --list "v${BASE_VERSION}-${FROM_CHANNEL}.*" --sort=-v:refname | head -n 1)
Tff7b72if [ -z "$LATEST_TAG_TO_PROMOTE" ]; then
Tff7b72echo "::error::No ${FROM_CHANNEL} release found for base version ${BASE_VERSION} to promote."
Tff7b72exit 1
Tff7b72fi
Tff7b72echo "Found latest ${FROM_CHANNEL} tag to promote: $LATEST_TAG_TO_PROMOTE"
Tff7b72# Calculate the increment for the TARGET channel
Tff7b72if [[ "$CHANNEL" != "production" ]]; then
Tff7b72LATEST_CHANNEL_TAG=$(git tag --list "v${BASE_VERSION}-${CHANNEL}.*" --sort=-v:refname | head -n 1)
Tff7b72if [ -z "$LATEST_CHANNEL_TAG" ]; then
Tff7b72INCREMENT=1
Tff7b72else
Tff7b72INCREMENT=$(echo "$LATEST_CHANNEL_TAG" | sed -n "s/.*-${CHANNEL}\.\([0-9]*\)/\1/p" | awk '{print $1+1}')
Tff7b72fi
Tff7b72
Tff7b72NEW_TAG="v${BASE_VERSION}-${CHANNEL}.${INCREMENT}"
Tff7b72else
Tff7b72# Production is special, it has no increment
Tff7b72NEW_TAG="v${BASE_VERSION}"
Tff7b72fi
Tff7b72echo "New release name will be: $NEW_TAG"
Tff7b72echo "Final tag will be: $NEW_TAG"
Tff7b72{
Tff7b72echo "from_channel=${FROM_CHANNEL}"
Tff7b72echo "tag_to_process=${LATEST_TAG_TO_PROMOTE}"
Tff7b72echo "release_name=${NEW_TAG}"
Tff7b72echo "final_tag=${NEW_TAG}"
Tff7b72} >> "$GITHUB_OUTPUT"
Tff7b72fi
Tff7b72shellTb4b4b4: Ta5d6ffbash
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffCreateTa5d6ff Ta5d6ffandTa5d6ff Ta5d6ffPushTa5d6ff Ta5d6ffReleaseTa5d6ff Ta5d6ffTag
Tff7b72ifTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ff!inputs.dry_runTa5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffinputs.channelTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'internal'Ta5d6ff Ta5d6ff}}
Tff7b72envTb4b4b4:
Tff7b72FINAL_TAGTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffsteps.calculate_tags.outputs.final_tagTa5d6ff Ta5d6ff}}
Tff7b72runTb4b4b4: Tb4b4b4|
Tff7b72echo "Tagging and pushing release: $FINAL_TAG"
Tff7b72git tag "$FINAL_TAG"
Tff7b72git push origin "$FINAL_TAG"
Tff7b72shellTb4b4b4: Ta5d6ffbash
Tff7b72call-release-workflowTb4b4b4:
Tff7b72ifTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ff!inputs.dry_runTa5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffinputs.channelTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'internal'Ta5d6ff Ta5d6ff}}
Tff7b72needsTb4b4b4: Ta5d6ffdetermine-tags
Tff7b72usesTb4b4b4: Ta5d6ff./.github/workflows/release.yml
Tff7b72withTb4b4b4:
Tff7b72tag_nameTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffneeds.determine-tags.outputs.final_tagTa5d6ff Ta5d6ff}}
Tff7b72channelTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffinputs.channelTa5d6ff Ta5d6ff}}
Tff7b72base_versionTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffinputs.base_versionTa5d6ff Ta5d6ff}}
Tff7b72build_desktopTb4b4b4: Ta5d6fftrue
Tff7b72build_flatpak_srcTb4b4b4: Ta5d6fftrue
Tff7b72secretsTb4b4b4: Ta5d6ffinherit
Tff7b72call-promote-workflowTb4b4b4:
Tff7b72ifTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ff!inputs.dry_runTa5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffinputs.channelTa5d6ff Ta5d6ff!=Ta5d6ff Ta5d6ff'internal'Ta5d6ff Ta5d6ff}}
Tff7b72needsTb4b4b4: Ta5d6ffdetermine-tags
T8b949e# promote.yml's token is capped by this job's grants, and a called
T8b949e# workflow requesting more than its caller grants fails at startup —
T8b949e# so this must cover promote.yml's declared workflow-level set, plus
T8b949e# actions: write for its publish-workflow dispatch. Scoped to this job
T8b949e# so call-release-workflow doesn't carry it.
Tff7b72permissionsTb4b4b4:
Tff7b72contentsTb4b4b4: Ta5d6ffwrite
Tff7b72pull-requestsTb4b4b4: Ta5d6ffwrite
Tff7b72statusesTb4b4b4: Ta5d6ffwrite
Tff7b72id-tokenTb4b4b4: Ta5d6ffwrite
Tff7b72attestationsTb4b4b4: Ta5d6ffwrite
Tff7b72actionsTb4b4b4: Ta5d6ffwrite
Tff7b72usesTb4b4b4: Ta5d6ff./.github/workflows/promote.yml
Tff7b72withTb4b4b4:
Tff7b72tag_nameTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffneeds.determine-tags.outputs.tag_to_processTa5d6ff Ta5d6ff}}
Tff7b72release_nameTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffneeds.determine-tags.outputs.release_nameTa5d6ff Ta5d6ff}}
Tff7b72final_tagTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffneeds.determine-tags.outputs.final_tagTa5d6ff Ta5d6ff}}
Tff7b72channelTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffinputs.channelTa5d6ff Ta5d6ff}}
Tff7b72base_versionTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffinputs.base_versionTa5d6ff Ta5d6ff}}
Tff7b72from_channelTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffneeds.determine-tags.outputs.from_channelTa5d6ff Ta5d6ff}}
Tff7b72secretsTb4b4b4: Ta5d6ffinherit
Tff7b72cleanup-on-failureTb4b4b4:
Tff7b72needsTb4b4b4: Tb4b4b4[Te6edf3determine-tagsTb4b4b4, Te6edf3call-release-workflowTb4b4b4]
Tff7b72ifTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ff(failure()Ta5d6ff Ta5d6ff||Ta5d6ff Ta5d6ffcancelled())Ta5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ff!inputs.dry_runTa5d6ff Ta5d6ff&&Ta5d6ff Ta5d6ffinputs.channelTa5d6ff Ta5d6ff==Ta5d6ff Ta5d6ff'internal'Ta5d6ff Ta5d6ff}}
Tff7b72runs-onTb4b4b4: Ta5d6ffubuntu-24.04-arm
Tff7b72timeout-minutesTb4b4b4: Ta5d6ff10
Tff7b72stepsTb4b4b4:
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffCheckoutTa5d6ff Ta5d6ffcode
Tff7b72usesTb4b4b4: Ta5d6ffactions/checkout@v7.0.1
Tff7b72withTb4b4b4:
Tff7b72fetch-depthTb4b4b4: Ta5d6ff0
Tb4b4b4- Tff7b72nameTb4b4b4: Ta5d6ffDeleteTa5d6ff Ta5d6ffFailedTa5d6ff Ta5d6fforTa5d6ff Ta5d6ffCancelledTa5d6ff Ta5d6ffTag
Tff7b72envTb4b4b4:
Tff7b72FINAL_TAGTb4b4b4: Ta5d6ff${{Ta5d6ff Ta5d6ffneeds.determine-tags.outputs.final_tagTa5d6ff Ta5d6ff}}
Tff7b72runTb4b4b4: Tb4b4b4|
Tff7b72if [ -n "$FINAL_TAG" ]; then
Tff7b72echo "Release workflow failed or was cancelled. Deleting tag $FINAL_TAG to allow a clean retry..."
Tff7b72git push origin :refs/tags/"$FINAL_TAG" || echo "Tag was not pushed or already deleted."
Tff7b72else
Tff7b72echo "No tag was created to delete."
Tff7b72fi
Served by rngit 1.5.2 - Generated in 0.09s